package cn.com.infcn.monitor.listener;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class IFCSessionListener implements HttpSessionListener, HttpSessionActivationListener,
		ServletContextListener, Serializable {
	private static final String SESSION_ACTIVATION_KEY = "javamelody.sessionActivation";
	private static final long serialVersionUID = -1624944319058843901L;
	private static final AtomicInteger SESSION_COUNT = new AtomicInteger();

	@SuppressWarnings("all")
	private static final List<String> CONTEXT_PATHS = new ArrayList<String>();

	@SuppressWarnings("all")
	private static final ConcurrentMap<String, HttpSession> SESSION_MAP_BY_ID = new ConcurrentHashMap<String, HttpSession>();


	static final class SessionInformationsComparator implements Comparator<IFCSessionInformations>,
			Serializable {
		private static final long serialVersionUID = 1L;

		@Override
		public int compare(IFCSessionInformations session1, IFCSessionInformations session2) {
			if (session1.getLastAccess().before(session2.getLastAccess())) {
				return 1;
			} else if (session1.getLastAccess().after(session2.getLastAccess())) {
				return -1;
			} else {
				return 0;
			}
		}
	}

	//获取当前在线用户数
	public static int getSessionCount() {
		return SESSION_COUNT.get();
	}

	//获取当前用户总在线时长
	public static long getSessionAgeSum() {
		final long now = System.currentTimeMillis();
		long result = 0;
		for (final HttpSession session : SESSION_MAP_BY_ID.values()) {
			try {
				result += now - session.getCreationTime();
			} catch (final Exception e) {
				continue;
			}
		}
		return result;
	}

	//注销所有Session
	static void invalidateAllSessions() {
		invalidateAllSessionsExceptCurrentSession(null);
	}

	// 注销其它用户所有session
	static void invalidateAllSessionsExceptCurrentSession(HttpSession currentSession) {
		for (final HttpSession session : SESSION_MAP_BY_ID.values()) {
			try {
				if (currentSession != null && currentSession.getId().equals(session.getId())) {
					continue;
				}
				session.invalidate();
			} catch (final Exception e) {
				continue;
			}
		}
	}

	//根据sessionID  注销session
	static void invalidateSession(String sessionId) {
		final HttpSession session = SESSION_MAP_BY_ID.get(sessionId);
		if (session != null) {
			try {
				session.invalidate();
			} catch (final Exception e) {
				return;
			}
		}
	}

	/**
	 * 获取所有的监控信息
	 * @return
	 */
	public static List<IFCSessionInformations> getAllSessionsInformations() {
		final Collection<HttpSession> sessions = SESSION_MAP_BY_ID.values();
		final List<IFCSessionInformations> sessionsInformations = new ArrayList<IFCSessionInformations>(
				sessions.size());
		for (final HttpSession session : sessions) {
			try {
				sessionsInformations.add(new IFCSessionInformations(session, false));
			} catch (final Exception e) {
				continue;
			}
		}
		sortSessions(sessionsInformations);
		return Collections.unmodifiableList(sessionsInformations);
	}

	//根据用户的最后访问时间进行session 排序
	static List<IFCSessionInformations> sortSessions(List<IFCSessionInformations> sessionsInformations) {
		if (sessionsInformations.size() > 1) {
			Collections.sort(sessionsInformations,
					Collections.reverseOrder(new SessionInformationsComparator()));
		}
		return sessionsInformations;
	}

	//根据sessionId 获取IFCSessionInformations 信息
	static IFCSessionInformations getSessionInformationsBySessionId(String sessionId) {
		final HttpSession session = SESSION_MAP_BY_ID.get(sessionId);
		if (session == null) {
			return null;
		}
		try {
			return new IFCSessionInformations(session, true);
		} catch (final Exception e) {
			return null;
		}
	}

	/**
	 * ServletContextListener 创建（系统启动调用）
	 */
	@Override
	public void contextInitialized(ServletContextEvent event) {
		final long start = System.currentTimeMillis();
		System.getProperty("java.io.tmpdir");

		final String contextPath = event.getServletContext().getContextPath();
		CONTEXT_PATHS.add(contextPath);

		System.out.println("JavaMelody listener init started");

		final long duration = System.currentTimeMillis() - start;
		System.out.println("JavaMelody listener init done in " + duration + " ms");
	}

	/**
	 * ServletContextListener 销毁（系统停止调用）
	 */
	@Override
	public void contextDestroyed(ServletContextEvent event) {
		SESSION_MAP_BY_ID.clear();
		SESSION_COUNT.set(0);
		System.out.println("JavaMelody listener destroy done");
	}

	/**
	 * 创建session
	 */
	@Override
	public void sessionCreated(HttpSessionEvent event) {
		final HttpSession session = event.getSession();
		if (session.getAttribute(SESSION_ACTIVATION_KEY) == this) {
			for (final Map.Entry<String, HttpSession> entry : SESSION_MAP_BY_ID.entrySet()) {
				final String id = entry.getKey();
				final HttpSession other = entry.getValue();
				if (!id.equals(other.getId())) {
					SESSION_MAP_BY_ID.remove(id);
				}
			}
		} else {
			session.setAttribute(SESSION_ACTIVATION_KEY, this);

			// pour getSessionCount
			SESSION_COUNT.incrementAndGet();
		}

		// pour invalidateAllSession
		SESSION_MAP_BY_ID.put(session.getId(), session);
	}

	/**
	 * 销毁session
	 */
	@Override
	public void sessionDestroyed(HttpSessionEvent event) {
		final HttpSession session = event.getSession();

		// pour getSessionCount
		SESSION_COUNT.decrementAndGet();

		// pour invalidateAllSession
		SESSION_MAP_BY_ID.remove(session.getId());
	}

	/**
	 * 活化session
	 */
	@Override
	public void sessionDidActivate(HttpSessionEvent event) {
		// pour getSessionCount
		SESSION_COUNT.incrementAndGet();

		// pour invalidateAllSession
		SESSION_MAP_BY_ID.put(event.getSession().getId(), event.getSession());
	}

	/**
	 * 钝化session
	 */
	@Override
	public void sessionWillPassivate(HttpSessionEvent event) {
		// pour getSessionCount
		SESSION_COUNT.decrementAndGet();

		// pour invalidateAllSession
		SESSION_MAP_BY_ID.remove(event.getSession().getId());
	}

	void registerSessionIfNeeded(HttpSession session) {
		if (session != null) {
			synchronized (session) {
				if (!SESSION_MAP_BY_ID.containsKey(session.getId())) {
					sessionCreated(new HttpSessionEvent(session));
				}
			}
		}
	}

	void unregisterSessionIfNeeded(HttpSession session) {
		if (session != null) {
			try {
				session.getCreationTime();

				session.getLastAccessedTime();
			} catch (final IllegalStateException e) {
				synchronized (session) {
					sessionDestroyed(new HttpSessionEvent(session));
				}
			}
		}
	}

	void unregisterInvalidatedSessions() {
		for (final HttpSession session : SESSION_MAP_BY_ID.values()) {
			unregisterSessionIfNeeded(session);
		}
		SESSION_COUNT.set(SESSION_MAP_BY_ID.size());
	}

	void removeAllActivationListeners() {
		for (final HttpSession session : SESSION_MAP_BY_ID.values()) {
			try {
				session.removeAttribute(SESSION_ACTIVATION_KEY);
			} catch (final Exception e) {
				continue;
			}
		}
	}

	@Override
	public String toString() {
		return getClass().getSimpleName() + "[sessionCount=" + getSessionCount() + ']';
	}
}
